package com.gr.staffpm.charts;

import java.awt.BasicStroke;
import java.awt.Color;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import org.apache.wicket.model.IModel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.Marker;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.TextAnchor;

import com.gr.staffpm.datatypes.Task;


public class CreatedVsResolvedChartGenerator implements ChartGenerator {

    private final JFreeChart chart;

    //private static final Logger log = Logger.getLogger(CreatedVsResolvedChartGenerator.class);

    public CreatedVsResolvedChartGenerator(int forLastDays, List<Task> createdTasks, List<Task> resolvedTasks) {
        this(createDataset(forLastDays, createdTasks, resolvedTasks), null);
    }

    public CreatedVsResolvedChartGenerator(XYDataset createdVsResolved) {
        this(createdVsResolved, null);
    }

    public CreatedVsResolvedChartGenerator(XYDataset createdVsResolved, List<Marker> domainMarkers) {

        boolean legend = true;
        boolean tooltips = true;
        boolean urls = false;

        chart = ChartFactory.createTimeSeriesChart("", "", "", createdVsResolved, legend, tooltips, urls);

        chart.setBackgroundPaint(Color.white);

        XYPlot plot = (XYPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.white);
        plot.setDomainGridlinePaint(Color.lightGray);
        plot.setRangeGridlinePaint(Color.lightGray);
        plot.setDomainCrosshairVisible(true);
        plot.setRangeCrosshairVisible(true);

        XYItemRenderer r = plot.getRenderer();
        if (r instanceof XYLineAndShapeRenderer) {
            XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;
            renderer.setBaseShapesVisible(true);
            renderer.setBaseShapesFilled(true);
            renderer.setBaseToolTipGenerator(new CreatedVsResolvedToolTipGenerator());
            renderer.setSeriesPaint(0, Color.red);
            renderer.setSeriesPaint(1, Color.green);
            renderer.setSeriesStroke(0, new BasicStroke(4f, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL));
            renderer.setSeriesStroke(1, new BasicStroke(4f, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL));
        }

        DateAxis domainAxis = (DateAxis) plot.getDomainAxis();
        domainAxis.setDateFormatOverride(new SimpleDateFormat("dd-MMM"));

        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setAutoRangeMinimumSize(10);
        rangeAxis.setLowerBound(0);

        if (domainMarkers != null && !domainMarkers.isEmpty()) {
            for (Iterator<Marker> iterator = domainMarkers.iterator(); iterator.hasNext();) {
                ValueMarker valueMarker = (ValueMarker) iterator.next();
                valueMarker.setLabelAnchor(RectangleAnchor.TOP_LEFT);
                valueMarker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
                plot.addDomainMarker(valueMarker);
            }
        }
    }

    @Override
    public ChartHelper generateChart() {
        return new ChartHelper(chart);
    }

    public IModel<JFreeChart> getChartModel() {
        return new LoadableDetachableJFChart(chart);
    }

    private static XYDataset createDataset(int forLastDays, List<Task> tasksCreated, List<Task> tasksResolved) {
        final TimeSeries createdSeries = new TimeSeries("Created");
        final TimeSeries resolvedSeries = new TimeSeries("Resolved");

        SimpleDateFormat dForm = new SimpleDateFormat("dd-MMM-yyyy");

        //log.info("Tasks Created in last " + forLastDays + " days: " + tasksCreated.size());
        //log.info("Tasks Resolved in last " + forLastDays + " days: " + tasksResolved.size());

        Iterator<Task> taskCreatedIterator = tasksCreated.iterator();
        Iterator<Task> taskResolvedIterator = tasksResolved.iterator();
        String taskCreatedDate = "", taskResolvedDate = "", date = "";
        Task taskCreated = null, taskResolved = null;

        if (!tasksCreated.isEmpty())
            taskCreated = taskCreatedIterator.next();
        if (!tasksResolved.isEmpty())
            taskResolved = taskResolvedIterator.next();

        for (int i = 0; i < forLastDays; i++) {
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.DAY_OF_MONTH, (-forLastDays + i));
            int noResolvedTasks = 0, noCreatedTasks = 0;

            date = dForm.format(cal.getTime());
            if (taskCreated != null)
                taskCreatedDate = dForm.format(taskCreated.getCreated());
            if (taskResolved != null)
                taskResolvedDate = dForm.format(taskResolved.getResolvedDate());

            while (date.equals(taskCreatedDate)) {
                noCreatedTasks++;
                if (taskCreatedIterator.hasNext()) {
                    taskCreated = taskCreatedIterator.next();
                    taskCreatedDate = dForm.format(taskCreated.getCreated());
                } else
                    break;
            }
            while (date.equals(taskResolvedDate)) {
                noResolvedTasks++;
                if (taskResolvedIterator.hasNext()) {
                    taskResolved = taskResolvedIterator.next();
                    taskResolvedDate = dForm.format(taskResolved.getResolvedDate());
                } else
                    break;
            }
            resolvedSeries.addOrUpdate(new Day(cal.getTime()), noResolvedTasks);
            createdSeries.addOrUpdate(new Day(cal.getTime()), noCreatedTasks);
        }

        final TimeSeriesCollection dataset = new TimeSeriesCollection();
        dataset.addSeries(createdSeries);
        dataset.addSeries(resolvedSeries);

        return dataset;
    }

}
